﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Dotnet.Utils.Utility.CollectionUtil
{
    public static class ExpressionUtil
    {
        public static Expression<Func<T, TKey>> GetOrderExpression<T, TKey>(string propertyName)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameterExpression, propertyName), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.Equal(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateNotEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.NotEqual(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateGreaterThan<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateLessThan<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.LessThan(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateGreaterThanOrEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> CreateLessThanOrEqual<T, S>(string propertyName, S propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression left = Expression.PropertyOrField(parameterExpression, propertyName);
            ConstantExpression right = Expression.Constant(propertyValue, typeof(S));
            return Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(left, right), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> GetContains<T>(string propertyName, string propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression instance = Expression.PropertyOrField(parameterExpression, propertyName);
            MethodInfo method = typeof(string).GetMethod("Contains", new Type[]
            {
                typeof(string)
            });
            ConstantExpression constantExpression = Expression.Constant(propertyValue, typeof(string));
            return Expression.Lambda<Func<T, bool>>(Expression.Call(instance, method, constantExpression), new ParameterExpression[]
            {
                parameterExpression
            });
        }

        public static Expression<Func<T, bool>> GetNotContains<T>(string propertyName, string propertyValue)
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "p");
            MemberExpression instance = Expression.PropertyOrField(parameterExpression, propertyName);
            MethodInfo method = typeof(string).GetMethod("Contains", new Type[]
            {
                typeof(string)
            });
            ConstantExpression constantExpression = Expression.Constant(propertyValue, typeof(string));
            return Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(instance, method, constantExpression)), new ParameterExpression[]
            {
                parameterExpression
            });
        }
    }
}